package com.sefer.dragonfly.client.confige;

import static com.sefer.dragonfly.client.constants.Constants.DEFAULT_CM_MONITOR_FILE;
import static com.sefer.dragonfly.client.constants.Constants.PERSONAL_CM_MONITOR_FILE;

import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.text.MessageFormat;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.digester.Digester;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.xml.sax.SAXException;

import com.sefer.dragonfly.client.confige.pojo.CmCachePojo;
import com.sefer.dragonfly.client.confige.pojo.CmCaches;
import com.sefer.dragonfly.client.confige.pojo.CmLocal;
import com.sefer.dragonfly.client.confige.pojo.CmMonitor;
import com.sefer.dragonfly.client.constants.CachePolicyEnum;
import com.sefer.dragonfly.client.constants.Constants;
import com.sefer.dragonfly.client.core.cache.CmCache;
import com.sefer.dragonfly.client.core.cache.CmCacheMuster;
import com.sefer.dragonfly.client.core.cache.CmCachePolicy;
import com.sefer.dragonfly.client.core.domain.CmConsumer;
import com.sefer.dragonfly.client.core.domain.CmConsumerChain;
import com.sefer.dragonfly.client.core.exception.DragonFlyRuntimeException;
import com.sefer.dragonfly.client.core.helper.CmCacheFactory;
import com.sefer.dragonfly.client.tools.CmCacheTools;

/**
 * 监控配置解析工具
 * 
 * @author xiaofeng 2011-11-2 下午01:34:55
 */
public class MonitorConfige {

	private static final Logger logger = Logger.getLogger(MonitorConfige.class);
	private static final CmCache<Serializable> Serializable = null;

	public CmMonitor parseMonitorXml(String xmlFilePath) {
		// 读取配置文件
		Digester digester = new Digester();
		URL url = MonitorConfige.class
				.getResource("/monitor/default_cmmonitor.dtd");
		digester.register("//dragonfly_cmmonitor.dtd/", url.toString());
		digester.setValidating(true);
		digester.addObjectCreate("cmonitor", CmMonitor.class);
		digester.addSetProperties("cmonitor");

		digester.addObjectCreate("cmonitor/local", CmLocal.class);
		digester.addSetNext("cmonitor/local", "setLocal",
				"com.sefer.dragonfly.client.confige.pojo.CmLocal");

		digester.addObjectCreate("cmonitor/local/caches", CmCaches.class);
		digester.addSetNext("cmonitor/local/caches", "setCaches",
				"com.sefer.dragonfly.client.confige.pojo.CmCaches");

		digester.addObjectCreate("cmonitor/local/caches/cache",
				CmCachePojo.class);
		digester.addSetProperties("cmonitor/local/caches/cache");
		digester.addSetProperties("cmonitor/local/caches/cache", "default",
				"isDefault");
		digester.addCallMethod("cmonitor/local/caches/cache/class", "setClazz",
				0);
		digester.addCallMethod("cmonitor/local/caches/cache/maxsize",
				"setMaxsize", 0, new String[] { "java.lang.Integer" });
		digester.addCallMethod("cmonitor/local/caches/cache/policy",
				"setPolicy", 0);

		digester.addSetNext("cmonitor/local/caches/cache", "add",
				"com.sefer.dragonfly.client.confige.pojo.CmCachePojo");

		// ===============>>>

		digester.addObjectCreate("cmonitor/local/consumers",
				CmConsumerChain.class);

		digester.addRule("cmonitor/local/consumers/consumer/clazz",
				new PluginRule());
		digester.addCallMethod("cmonitor/local/consumers/consumer/version",
				"setVersion", 0);
		digester.addCallMethod("cmonitor/local/consumers/consumer/namespace",
				"setNameSpace", 0);
		digester.addCallMethod("cmonitor/local/consumers/consumer/consumerId",
				"setConsumerId", 0);
		digester.addCallMethod("cmonitor/local/consumers/consumer/notify",
				"setNotifyServer", 0, new String[] { "java.lang.Boolean" });
		digester.addCallMethod("cmonitor/local/consumers/consumer/priority",
				"setPriority", 0, new String[] { "java.lang.Integer" });
		digester.addCallMethod(
				"cmonitor/local/consumers/consumer/cronExpression",
				"setCronExpression", 0);
		digester.addCallMethod("cmonitor/local/consumers/consumer/cacheId",
				"setCacheId", 0);
		digester.addCallMethod("cmonitor/local/consumers/consumer/needCache",
				"setNeedCache", 0, new String[] { "java.lang.Boolean" });
		digester.addRule("cmonitor/local/consumers/consumer",
				new PluginAddRule("addCmConsumer",
						"com.sefer.dragonfly.client.core.domain.CmConsumer"));

		digester.addSetNext("cmonitor/local/consumers", "setChain",
				"com.sefer.dragonfly.client.core.domain.CmConsumerChain");

		InputStream resourceAsStream = MonitorConfige.class
				.getResourceAsStream(xmlFilePath);
		if (resourceAsStream != null) {
			try {
				return (CmMonitor) digester.parse(resourceAsStream);
			} catch (IOException e) {
				logger.error(e.getMessage(), e);
			} catch (SAXException e) {
				logger.error(e.getMessage(), e);
			}
		}
		return null;
	}

	public CmMonitor mergeMonitorConfige(CmMonitor defaultCmMonitor,
			CmMonitor personalCmMonitor) {
		if (defaultCmMonitor == null) {
			return personalCmMonitor;
		}
		if (personalCmMonitor == null) {
			return defaultCmMonitor;
		}

		CmLocal defaultLocal = defaultCmMonitor.getLocal();
		CmLocal personalLocal = personalCmMonitor.getLocal();
		if (defaultLocal == null && personalLocal != null) {
			defaultLocal = personalLocal;
		}
		if (defaultLocal != null && personalLocal != null) {
			// 缓存整合
			CmCaches defaultCmCaches = defaultLocal.getCaches();
			CmCaches personalCmCaches = personalLocal.getCaches();
			if (defaultCmCaches == null && personalCmCaches != null) {
				defaultCmCaches = personalCmCaches;
			}
			if (defaultCmCaches != null && personalCmCaches != null) {
				// 默认的配置是不允许修改的
				List<CmCachePojo> personalAddPluginList = new LinkedList<CmCachePojo>();
				boolean isFind = false;
				for (CmCachePojo pcmCache : personalCmCaches.getLists()) {
					isFind = false;
					for (CmCachePojo dcmCache : defaultCmCaches.getLists()) {
						if (pcmCache.getId().equals(dcmCache.getId())) {
							dcmCache = pcmCache;
							isFind = true;
						}
					}
					if (!isFind) {
						personalAddPluginList.add(pcmCache);
					}
				}
				// 把自定义的缓存配置加入到默认项
				for (CmCachePojo cache : personalAddPluginList) {
					defaultCmCaches.add(cache);
				}
			}
			// 插件消费者整合
			CmConsumerChain chain = defaultLocal.getChain();
			CmConsumerChain chain2 = personalLocal.getChain();

			if (chain != null) {
				if (chain2 != null) {
					chain.addAll(chain2);
				}

			}

		}

		return defaultCmMonitor;
	}

	/**
	 * 构建缓存和消费者列表
	 * 
	 * @param cacheMuster
	 * @param pluginChain
	 * @return
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public void buildMonitorConfige(
			CmCacheMuster<String, Serializable> cacheMuster,
			CmConsumerChain consumerChain) {

		if (cacheMuster == null || consumerChain == null) {
			throw new DragonFlyRuntimeException(
					"BuildMonitorConfige exception , params is null.May be the container is not inited.");
		}

		CmMonitor defaultMnitor = this.parseMonitorXml(DEFAULT_CM_MONITOR_FILE);

		CmMonitor personalMnitor = this
				.parseMonitorXml(PERSONAL_CM_MONITOR_FILE);

		defaultMnitor = mergeMonitorConfige(defaultMnitor, personalMnitor);

		List<com.sefer.dragonfly.client.confige.pojo.CmCachePojo> lists = defaultMnitor
				.getLocal().getCaches().getLists();

		if (lists != null) {
			for (com.sefer.dragonfly.client.confige.pojo.CmCachePojo cache : lists) {
				String clazz = cache.getClazz();
				Class<?> forName = null;
				CmCache<Serializable> cmCache = null;
				if (StringUtils.isBlank(clazz)) {
					// 空则提供给默认配置缓存实现
					cmCache = CmCacheFactory.<Serializable> createCmCache();
				} else {
					try {
						forName = Class.forName(clazz);
						if (forName != null) {
							cmCache = (CmCache) forName.newInstance();

						} else {
							// 创建默认的缓存类
							cmCache = CmCacheFactory
									.<Serializable> createCmCache();
						}
					} catch (ClassNotFoundException e) {
						logger.error(e.getMessage(), e);
						throw new DragonFlyRuntimeException(
								MessageFormat
										.format("class not find exception : {0}  , when init cmcache in MonitorContainer",
												clazz));
					} catch (InstantiationException e) {
						logger.error(e.getMessage(), e);
						throw new DragonFlyRuntimeException(
								MessageFormat
										.format("Can't instance exception : {0}  , when init cmcache in MonitorContainer",
												clazz));
					} catch (IllegalAccessException e) {
						logger.error(e.getMessage(), e);
						throw new DragonFlyRuntimeException(
								MessageFormat
										.format("Can't instance exception : {0}  , when init cmcache in MonitorContainer",
												clazz));
					}
				}

				cmCache.setMaxSize(cache.getMaxsize());

				// 删除和存储策略
				CmCachePolicy policy = new CmCachePolicy();
				if (StringUtils.isNotBlank(cache.getPolicy())) {
					policy.setPolicy(CachePolicyEnum.getPolicy(cache
							.getPolicy()));
				}

				cmCache.setCmCachePolicy(policy);
				cacheMuster.addCmCache(cache.getId(), cmCache);
			}

			// 对于信息不足的，用默认配置项补全
			CmCache<Serializable> defaultCmCache = cacheMuster
					.getCmCache(Constants.DEFAULT_CACHE_KEY);

			Map<String, CmCache<Serializable>> allCache = cacheMuster
					.getAllCache();
			for (String key : allCache.keySet()) {
				if (StringUtils.equals(key, Constants.DEFAULT_CACHE_KEY)) {
					continue;
				}
				CmCache<Serializable> cmCacheTmp = cacheMuster.getCmCache(key);
				if (cmCacheTmp.getMaxSize() == 0) {
					cmCacheTmp.setMaxSize(defaultCmCache.getMaxSize());
				}

				CmCachePolicy cmCachePolicy = cmCacheTmp.getCmCachePolicy();
				if (cmCachePolicy == null) {
					cmCacheTmp.setCmCachePolicy(defaultCmCache
							.getCmCachePolicy());
				} else {
					if (cmCachePolicy.getPolicy() == null) {
						cmCachePolicy.setPolicy(defaultCmCache
								.getCmCachePolicy().getPolicy());
					}
				}
			}
		}

		// 配置消费者插件
		CmConsumerChain chain = defaultMnitor.getLocal().getChain();
		if (chain != null) {
			for (CmConsumer plugin : chain.getCmConsumers()) {

				// 如果缓存集合中没有指定缓存且指定需要缓存，则默认提供
				if (cacheMuster.getCmCache(plugin.getCacheId()) == null
						&& plugin.isNeedCache()) {

					CmCache<Serializable> cmcache = null;
					try {
						cmcache = (CmCache<Serializable>) BeanUtils
								.cloneBean(cacheMuster
										.getCmCache(Constants.DEFAULT_CACHE_KEY));
					} catch (IllegalAccessException e) {
						logger.error(MessageFormat.format(
								"default Cmcache clone exception , {0}",
								e.getMessage()), e);
					} catch (InstantiationException e) {
						logger.error(MessageFormat.format(
								"default Cmcache clone exception , {0}",
								e.getMessage()), e);
					} catch (InvocationTargetException e) {
						logger.error(MessageFormat.format(
								"default Cmcache clone exception , {0}",
								e.getMessage()), e);
					} catch (NoSuchMethodException e) {
						logger.error(MessageFormat.format(
								"default Cmcache clone exception , {0}",
								e.getMessage()), e);
					}
					cacheMuster.addCmCache(CmCacheTools.generateKey(
							plugin.getConsumerId(), plugin.getVersion()),
							cmcache);
					plugin.setCacheId(CmCacheTools.generateKey(
							plugin.getConsumerId(), plugin.getVersion()));

				}
			}
			consumerChain.addAll(chain);
		}
	}

	// ====================
	public static void main(String[] args) {
		MonitorConfige confige = new MonitorConfige();
		CmMonitor s = confige.parseMonitorXml(DEFAULT_CM_MONITOR_FILE);
		System.out.println(s.getLocal());
		CmMonitor c = confige.parseMonitorXml(PERSONAL_CM_MONITOR_FILE);
		System.out.println(c.getLocal());

	}
}
